<?php
namespace Org\WxAppPay;
use Org\WxAppPay\WxPayConfig;
/**
 * Created by PhpStorm.
 * User: moko1988
 * Date: 16/4/22
 * Time: 下午4:15
 */
class WxPayApi{

    protected $appid = WxPayConfig::APPID;
    protected $mch_id = WxPayConfig::MCHID;
    protected $key = WxPayConfig::KEY;
    protected $appsecret = WxPayConfig::APPSECRET;

    /*统一下单*/
    public function getPrePayOrder($WxPayUnifiedOrder){


        $WxPayUnifiedOrder["appid"] = $this->appid;
        $WxPayUnifiedOrder["mch_id"] = $this->mch_id;
        $WxPayUnifiedOrder["nonce_str"] = $this->getRandChar(32);
        $WxPayUnifiedOrder["spbill_create_ip"] = get_client_ip();
        $WxPayUnifiedOrder["trade_type"] = "APP";
        $sign = $this->getSign($WxPayUnifiedOrder);
        $WxPayUnifiedOrder["sign"] = $sign;

        \Think\Log::write('统一下单提交参数:'.json_encode($WxPayUnifiedOrder),'INFO');

        //将数组参数转成axl格式
        $xml = $this->arrayToXml($WxPayUnifiedOrder);
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        //想微信服务器发送订单
        $response = $this->postXmlCurl($xml, $url);
        //将微信返回的结果xml转成数组
        $response = $this->xmlToArray($response);
        \Think\Log::write('统一下单返回值:'.json_encode($response),'INFO');

        //微信服务器返回成功(统一下单成功)
        if($response['return_code'] == 'SUCCESS' && $response['result_code'] == 'SUCCESS'){
            \Think\Log::write('统一下单成功','INFO');
            $sign = $this->getSign($response);
            //验证sign
            \Think\Log::write('统一下单sign:'.$response['sign'],'INFO');
            \Think\Log::write('统一下单验证sign:'.$sign,'INFO');
            if($sign == $response['sign']){
                //验证通过返回支付交易会话ID
                \Think\Log::write('统一下sign验证成功','INFO');
                $prepay_id = $response['prepay_id'];
            }else{
                \Think\Log::write('统一下sign验证失败','INFO');
                $prepay_id = false;
            }

        }else{

            $prepay_id = false;
        }

        return $prepay_id;
    }

    /*调起支付所需参数*/
    public function getPrePayParam($prepay_id){

        $response = array();
        $response['appid'] = $this->appid;
        $response['partnerid'] = $this->mch_id;
        $response['prepayid'] = $prepay_id;
        $response['package'] = 'Sign=WXPay';
        $response['noncestr'] = $this->getRandChar(32);
        $response['timestamp'] = time();
        $sign = $this->getSign($response);
        $response['sign'] = $sign;

        return $response;
    }


    /*支付通知验证*/
    public function checkNotify($notifyXml){

        $notifyData = $this->xmlToArray($notifyXml);

        \Think\Log::write('支付通知-返回值:'.json_encode($notifyData),'INFO');

        $sign = $this->getSign($notifyData);
        //验证sign
        if($sign == $notifyData['sign']){

            $returnData = $notifyData;
        }else{
            \Think\Log::write('支付通知sign验证不通过','INFO');
            $returnData = false;
        }

        return $returnData;

    }

    /*支付结果查询*/
    public function orderQuery($transaction_id){


        $queryData["appid"] = $this->appid;
        $queryData["mch_id"] = $this->mch_id;
        $queryData["transaction_id"] = $transaction_id;
        $queryData["nonce_str"] = $this->getRandChar(32);
        $sign = $this->getSign($queryData);
        $queryData["sign"] = $sign;

        \Think\Log::write('支付结果查询提交参数:'.json_encode($queryData),'INFO');

        //将数组参数转成axl格式
        $xml = $this->arrayToXml($queryData);
        $url = 'https://api.mch.weixin.qq.com/pay/orderquery';
        //向微信服务器发送请求
        $response = $this->postXmlCurl($xml, $url);
        //将微信返回的结果xml转成数组
        $response = $this->xmlToArray($response);
        \Think\Log::write('支付结果查询返回值:'.json_encode($response),'INFO');

        //微信服务器返回成功(查询订单成功)
        if($response['return_code'] == 'SUCCESS' && $response['result_code'] == 'SUCCESS'){
            \Think\Log::write('支付结果查询成功','INFO');
            $sign = $this->getSign($response);
            //验证sign
            if($sign == $response['sign']){
                \Think\Log::write('支付结果查询sign验证成功','INFO');
                //验证通过返回支付交易会话ID
                $returnData = $response;
            }else{
                \Think\Log::write('支付结果查询sign验证失败','INFO');
                $returnData = false;
            }

        }else{
            \Think\Log::write('支付结果查询失败','INFO');
            $returnData = false;
        }

        return $returnData;

    }

    //获取指定长度的随机字符串
    public function getRandChar($length){
        $str = null;
        $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
        $max = strlen($strPol)-1;

        for($i=0;$i<$length;$i++){
            $str.=$strPol[rand(0,$max)];//rand($min,$max)生成介于min和max两个数之间的一个随机整数
        }

        return $str;
    }

    /*
        生成签名
    */
    public function getSign($Parameters){

        //签名步骤一：按字典序排序参数
        ksort($Parameters);
        $String = $this->ToUrlParams($Parameters);
        //签名步骤二：在string后加入KEY
        $String = $String."&key=".$this->key;
        //签名步骤三：MD5加密
        $result_ = strtoupper(md5($String));
        return $result_;
    }


    //格式化参数格式化成url参数
    public function ToUrlParams($paraMap){

        $buff = "";
        foreach ($paraMap as $k => $v){
            if($k != "sign" && $v != "" && !is_array($v)){
                $buff .= $k . "=" . $v . "&";
            }
        }

        $buff = trim($buff, "&");
        return $buff;
    }

    //数组转xml
    public function arrayToXml($arr){
        $xml = "<xml>";
        foreach ($arr as $key=>$val){
            if (is_numeric($val)){
                $xml.="<".$key.">".$val."</".$key.">";

            }
            else{
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml;
    }

    /*xml转成数组*/
    public function xmlToArray($xmlstr) {
        if(!$xmlstr){
            die("xml数据异常！");
        }
        //将XML转为array
        //禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        $values = json_decode(json_encode(simplexml_load_string($xmlstr, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $values;
    }



    //post https请求，CURLOPT_POSTFIELDS xml格式
    public function postXmlCurl($xml,$url,$second=30){
        //初始化curl
        $ch = curl_init();
        //超时时间
        curl_setopt($ch,CURLOPT_TIMEOUT,$second);
        //这里设置代理，如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch,CURLOPT_URL, $url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,FALSE);
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //运行curl
        $data = curl_exec($ch);
        //返回结果
        if($data){
            curl_close($ch);
            return $data;
        }else{
            $error = curl_errno($ch);
            echo "curl出错，错误码:$error"."<br>";
            echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
            curl_close($ch);
            return false;
        }
    }


    /*通过code获取微信登录信息*/
    public function WxLoginCodeInfo($code){

        $urlObj["appid"] = $this->appid;
        $urlObj["secret"] = $this->appsecret;
        $urlObj["code"] = $code;
        $urlObj["grant_type"] = 'authorization_code';
        $bizString = $this->ToUrlParams($urlObj);
        $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?'.$bizString;

        $codeInfo = $this->getCurl($url);

        \Think\Log::write('微信登录CODE信息:'.json_encode($codeInfo),'INFO');

        return $codeInfo;

    }


    /*获取微信用户信息*/
    public function WxUserinfo($access_token, $openid){

        $urlObj["access_token"] = $access_token;
        $urlObj["openid"] = $openid;

        $bizString = $this->ToUrlParams($urlObj);
        $url = 'https://api.weixin.qq.com/sns/userinfo?'.$bizString;

        $userInfo = $this->getCurl($url);

        \Think\Log::write('微信登录用户信息:'.json_encode($userInfo),'INFO');

        return $userInfo;

    }



    /*获取微博用户信息*/
    public function WeiboUserinfo($uid, $token){

        $urlObj["uid"] = $uid;
        $urlObj["access_token"] = $token;

        $bizString = $this->ToUrlParams($urlObj);
        $url = 'https://api.weibo.com/2/users/show.json?'.$bizString;

        $userInfo = $this->getCurl($url);

        \Think\Log::write('微博登录用户信息:'.json_encode($userInfo),'INFO');

        return $userInfo;

    }


    private function getCurl($url, $timeout = 30){
        //初始化curl
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //运行curl，结果以jason形式返回
        $res = curl_exec($ch);
        curl_close($ch);
        $data = json_decode($res,true);
        return $data;
    }


}